﻿using System;
using java = biz.ritter.javapi.lang;
using biz.ritter.javapi.util;
using biz.ritter.javapi.lang;

namespace Nofs.Net.Cache.Impl
{
    public class MemoryBuffer : Iterable<java.Byte>
    {
        private int _position;
        private List<java.Byte[]> _buffers;
        private int _bufferSize;
        private int _extents;

        public MemoryBuffer(int incrementSize)
        {
            _extents = 0;
            _position = 0;
            _buffers = new LinkedList<java.Byte[]>();
            _bufferSize = incrementSize;
            _buffers.add(new java.Byte[incrementSize]);
        }

        public void Trim(int extent)
        {
            GrowBufferIfOffsetDoesNotExist(extent);
            for (int i = extent; i < _extents; i++)
            {
                putAt(new java.Byte((byte)0), i);
            }
            _extents = extent;
        }

        public int getSize()
        {
            return _extents;
        }

        private void GrowBufferIfOffsetDoesNotExist(int offset)
        {
            offset += 1;
            if (offset > _extents)
            {
                int maxExtents = _buffers.size() * _bufferSize;
                if (maxExtents >= offset)
                {
                    _extents = offset;
                }
                else
                {
                    _buffers.add(new java.Byte[_bufferSize]);
                    GrowBufferIfOffsetDoesNotExist(offset);
                }
            }
        }

        public void put(byte b)
        {
            put(new java.Byte(b));
        }

        public void put(java.Byte b)
        {
            putAt(b, _position++);
        }

        private void putAt(java.Byte b, int offset)
        {
            GrowBufferIfOffsetDoesNotExist(offset);
            int bufferPosition = offset / _bufferSize;
            int bufferOffset = offset % _bufferSize;
            _buffers.get(bufferPosition)[bufferOffset] = b;
        }

        public void put(java.Byte[] bytes)
        {
            foreach (java.Byte b in bytes)
            {
                put(b);
            }
        }

        public java.Byte get()
        {
            return getAt(_position++);
        }

        public java.Byte getAt(int offset)
        {
            if (offset + 1 > _extents)
            {
                throw new IndexOutOfBoundsException();
            }
            int bufferPosition = offset / _bufferSize;
            int bufferOffset = offset % _bufferSize;
            return _buffers.get(bufferPosition)[bufferOffset];
        }

        public java.Byte[] get(int length)
        {
            java.Byte[] data = new java.Byte[length];
            for (int i = 0; i < length; i++)
            {
                data[i] = getAt(_position + i);
            }
            _position += length;
            return data;
        }

        public int getPosition()
        {
            return _position;
        }

        public void setPosition(int value)
        {
            _position = value;
        }

        //@Override
        public Iterator<java.Byte> iterator()
        {
            return new MemoryBufferIterator(this, 0);
        }

        public System.Collections.Generic.IEnumerator<java.Byte> GetEnumerator()
        {
            for (int i = 0; i < _buffers.size(); ++i)
            {
                foreach(var v in _buffers.get(i))
                {
                    yield return v;
                }
            }
        }
      
        private class MemoryBufferIterator : Iterator<java.Byte>
        {

            private MemoryBuffer _buffer;
            private int _position;

            public MemoryBufferIterator(MemoryBuffer buffer, int position)
            {
                _buffer = buffer;
                _position = position;
            }

            //@Override
            public bool hasNext()
            {
                return _position < _buffer.getSize();
            }

            //@Override
            public java.Byte next()
            {
                return _buffer.getAt(_position++);
            }

            //@Override
            public void remove()
            {
            }
        }

        Iterator<java.Byte> Iterable<java.Byte>.iterator()
        {
            throw new NotImplementedException();
        }
    }

}
